﻿using System;
using System.IO;
using EmbeddedSharp.Core;

namespace EmbeddedSharp.Scripting.Function.Context {

    /// <summary>
    /// Load existed function libraries.
    /// </summary>
    [Function("import", "Load existed function libraries.", "import(\"combinatorics.ess\");echo(fib(5));", "10")]
    public class ImportNode : ContextFuncNode {

        /// <summary>
        /// Default constructor
        /// </summary>
        public ImportNode()
            : base("import") {
        }

        /// <summary>
        /// Evaluate the operation
        /// </summary>
        /// <returns></returns>
        public override object Evaluate() {
            int length = Parameters.Count;
            if (Parameters.Count < 0) {
                throw new ArgumentException(
                    "Usage: import(fileName | folder);");
            }

            string fileName = Parameters[length - 1].Value;
            if (fileName.EndsWith(".dll")) {
                if (Parameters.Count > 1) {
                    string funcName = Convert.ToString(
                        Parameters[length - 2]);
                    return this.LoadFromDll(fileName, funcName);
                }

                return this.LoadFromDll(fileName);
            } else if (Directory.Exists(fileName)) {
                return Load(fileName);
            }

            return false;
        }

        /// <summary>
        /// Load a new file from disk
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public bool Load(string path) {
            DefaultFunctionLoader dfl
                = new DefaultFunctionLoader(
                    DefaultDependencyManager.Instance.FunctionManager);
            dfl.LoadFromFile(path);

            return true;
        }

        public bool LoadFromDll(string fileName) {
            if (!File.Exists(fileName)) {
                return false;
            }

            DefaultFunctionLoader dfl
                = new DefaultFunctionLoader(
                    DefaultDependencyManager.Instance.FunctionManager);
            dfl.LoadFromFile(fileName);

            return true;
        }

        /// <summary>
        /// Load from Dynamic Link Library
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="functionName"></param>
        /// <returns></returns>
        public bool LoadFromDll(string fileName, string functionName) {
            return false;
        }

        /// <summary>
        /// Get the file name with extension
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string GetFileName(string name) {
            if (name.EndsWith(".fp") || name.EndsWith(".fpz")) {
                return name;
            }

            if (File.Exists(name + ".fp")) {
                return name + ".fp";
            }
            if (File.Exists(name + ".fpz")) {
                return name + ".fpz";
            }

            string fileName = Utils.FunctionPath.EndsWith("\\") ? Utils.FunctionPath + name + ".fp" : Utils.FunctionPath + name + ".fp";
            if (File.Exists(fileName)) {
                return fileName;
            }

            throw new FileNotFoundException(name);
        }

        /// <summary>
        /// Load from a text file
        /// </summary>
        /// <returns></returns>
        public bool LoadFile(string fileName) {
            try {
                fileName = GetFileName(fileName);
                string buff = File.ReadAllText(fileName);
                string[] stmts = buff.Split(';');
                foreach (string stmt in stmts) {
                    string s = stmt.Trim();
                    if (string.IsNullOrEmpty(stmt)) {
                        continue;
                    }

                    UserDefinedFunctionParser parser
                        = new UserDefinedFunctionParser(
                            this.Context.GetParserFactory());
                    UserDefinedFunctionNode udf = parser.Parse(s);
                    Context.GetFunctionManager().Add(udf.Name, udf);
                }

                return true;
            } catch (FileNotFoundException ex) {
                return false;
            }
        }
    }
}
